package common.shiro;

import com.auth0.jwt.exceptions.TokenExpiredException;

import com.google.gson.Gson;
import common.oauth2.OAuth2Token;
import common.oauth2.TokenUtil;
import common.redis.RedisUtils;
import dto.RedisDto;
import dto.SysMenuDto;
import dto.SysRoleDto;
import dto.SysUserDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import service.MenuService;
import service.RoleService;
import service.UserService;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public class ShiroRealm  extends AuthorizingRealm {

    @Autowired
    @Lazy
    private UserService userService;
    @Autowired
    @Lazy
    private RoleService roleService;
    @Autowired
    @Lazy
    private MenuService menuService;
//    @Autowired
//    private RedisUtils redisUtils;
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof OAuth2Token;
    }

    /**
     * 自定义用户授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("-------自定义用户授权----");
        SysUserDto user = (SysUserDto) principalCollection.getPrimaryPrincipal();
        Long userid = user.getUserId();
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        //.get(userid + "cache")
        String redis = (String) redisTemplate.opsForValue().get(userid + "cache");
        List<SysRoleDto> roleList=null;
        List<SysMenuDto> permissionList=null;
        if (redis != null) {
            RedisDto redisDto=new RedisDto();
            Gson gson=new Gson();
            redisDto=gson.fromJson(redis,RedisDto.class);
            log.info("从缓存中读取:"+redis);
             roleList=  redisDto.getRoleList();
             permissionList=redisDto.getPermissionList();
        }else {
            log.info("查询表");
             roleList = this.roleService.findUserRole(userid);
            permissionList = this.menuService.findUserPermissions(userid);
        }
        // 获取用户角色集
        Set<String> roleSet = roleList.stream().map(SysRoleDto::getRoleName).collect(Collectors.toSet());
        simpleAuthorizationInfo.setRoles(roleSet);

        // 获取用户权限集
    //    permissionList = this.menuService.findUserPermissions(userid);
        Set<String> permissionSet = new HashSet<>();
        for (SysMenuDto m : permissionList) {
            permissionSet.add(m.getPerms());
        }
        simpleAuthorizationInfo.setStringPermissions(permissionSet);
        return simpleAuthorizationInfo;
    }



    /**
     * 自定义用户认证
     * @param auth
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
        log.info("-------自定义用户认证----");
        String token = (String) auth.getCredentials();
        // 解密获得username，用于和数据库进行对比
        Long userid = TokenUtil.getUsernId(token);
        if (userid == null) {
            throw new AuthenticationException("token invalid");
        }
        String redis = (String)redisTemplate.opsForValue().get(userid + "cache");
        SysUserDto user=null;
        if (redis != null) {
            RedisDto redisDto=new RedisDto();
            Gson gson=new Gson();
            redisDto=gson.fromJson(redis,RedisDto.class);
            log.info("从缓存中读取:"+redis);

            user= redisDto.getUserDto();
        }else {
            log.info("查询表");
           user = userService.select(userid);
        }

        if (user == null) {
            throw new AuthenticationException("User didn't existed!");
        }

        try {
           TokenUtil.verify(token, userid, user.getPassword());
        } catch (UnsupportedEncodingException e) {
            throw new AuthenticationException("Username or password error");
        } catch (SecurityException e2){
            throw new AuthenticationException("Username or password error");
        } catch (TokenExpiredException e3){
            throw new AuthenticationException("Token expire");
        }

        return new SimpleAuthenticationInfo(user, token, getName());
    }
}
